﻿using System;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.InterceptionExtension;

namespace AopDemo
{

    #region Microsoft.Unity 

    #region 自定义CallHandler，这里定义两个CallHandler分别用于参数检查和日志记录。

    public class UserHandler : ICallHandler
    {
        public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
        {
            User user = input.Inputs[0] as User;
            if (user != null && user.PassWord.Length < 10)
            {
                return input.CreateExceptionMethodReturn(new Exception("密码长度不能小于10位"));
            }
            Console.WriteLine("参数检测无误");
            return getNext()(input, getNext);
        }

        public int Order { get; set; }
    }

    public class LogHandler : ICallHandler
    {
        public int Order { get; set; }

        public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
        {
            User user = input.Inputs[0] as User;
            Log log = new Log()
            {
                Message = string.Format("RegUser:Username:{0},Password:{1}", user.Name, user.PassWord),
                Ctime = DateTime.Now
            };
            Console.WriteLine("日志已记录，Message:{0},Ctime:{1}", log.Message, log.Ctime);
            var messagereturn = getNext()(input, getNext);
            return messagereturn;
        }
    }

    public class Log
    {
        public string Message { get; set; }
        public DateTime Ctime { get; set; }

    }

    #endregion

    #region 定义对应的HandlerAttribute

    public class UserHandlerAttribute : HandlerAttribute
    {
        public override ICallHandler CreateHandler(IUnityContainer container)
        {
            ICallHandler handler = new UserHandler() {Order = this.Order};
            return handler;
        }
    }

    public class LogHandlerAttribute : HandlerAttribute
    {
        public override ICallHandler CreateHandler(IUnityContainer container)
        {
            return new LogHandler() {Order = this.Order};
        }
    }

    #endregion

    #region 用户注册接口和实现，这里通过为接口添加attribute的方式实现。order值表示执行顺序，值小的先执行。

    [LogHandlerAttribute(Order = 2)]
    [UserHandlerAttribute(Order = 1)]
    public interface IUserProcessor3
    {
        void RegUser(User user);
    }

    public class UserProcessor3 : MarshalByRefObject, IUserProcessor3
    {
        public void RegUser(User user)
        {
            //todo 业务逻辑
            Console.WriteLine("UnityClient 用户已注册。");
        }
    }

    #endregion

    #region 客户端调用

    public class UnityClient
    {
        public static void Run()
        {
            //Unity默认提供了三种拦截器：TransparentProxyInterceptor、InterfaceInterceptor、VirtualMethodInterceptor。
            //TransparentProxyInterceptor：代理实现基于.NET Remoting技术，它可拦截对象的所有函数。缺点是被拦截类型必须派生于MarshalByRefObject。
            //InterfaceInterceptor：只能对一个接口做拦截，好处时只要目标类型实现了指定接口就可以拦截。
            //VirtualMethodInterceptor：对virtual函数进行拦截。缺点是如果被拦截类型没有virtual函数则无法拦截，这个时候如果类型实现了某个特定接口可以改用

            try
            {
                using (var container = new UnityContainer())
                {
                    User user = new User() {Name = "lee", PassWord = "123123123123"};
                    container.AddNewExtension<Interception>();
                    //1.TransparentProxyInterceptor
                    container.Configure<Interception>()
                        .SetInterceptorFor<IUserProcessor3>(new TransparentProxyInterceptor());
                    //2.InterfaceInterceptor (使用1,2,3均可,这种侵入性最小)
                    //container.Configure<Interception>().SetInterceptorFor<IUserProcessor3>(new InterfaceInterceptor());
                    //3.VirtualMethodInterceptor,实现类中的方法必须是虚方法
                    //container.Configure<Interception>().SetInterceptorFor<UserProcessor3>(new VirtualMethodInterceptor());
                    container.RegisterType<IUserProcessor3, UserProcessor3>();
                    container.Resolve<IUserProcessor3>().RegUser(user);
                }

            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
    }

    #endregion

    #endregion
}
